/*
#Copyright (c) 2013, Philippe Bordron <philippe.bordron@gmail.com>
#
# This file is part of SIPPER.
#
# DCC is free software: you can redistribute it and/or modify
# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU LESSER GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# along with SIPPER.  If not, see <http://www.gnu.org/licenses/>
*/
package combi.wip.sipper.exec;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import combi.sipper.io.InFlatFile;

/**
 * Compute the set of genes depending directly or/and indirectly of a regulator.
 * @author philippebordron
 *
 */

public class ExtractCommonRegulatorTU {

	private static String REGULATED_ENTITY = "REGULATED-ENTITY";
	private static String REGULATOR = "REGULATOR";
	private static String REGULATOR_MODE = "MODE";
	private static String COMPONENT_OF = "COMPONENT-OF";
	private static String COMPONENTS = "COMPONENTS";

	public static void main(String[] args) throws IOException
	{
		String fileRegulation = args[0];
		String directRegulation = args[1]; // d | i
		String fileOut = args[2];
		String fileTU = args[3];
		String filePromoters = args[4];
		String fileGenes = args[5];

		InFlatFile ioRegulation = new InFlatFile(fileRegulation);
		Map<String,Map<String, Collection<String>>> regulationMap = ioRegulation.readFile();
		InFlatFile ioTU = new InFlatFile(fileTU);
		Map<String,Map<String, Collection<String>>> tuMap = ioTU.readFile();
		InFlatFile ioPromoters = new InFlatFile(filePromoters);
		Map<String,Map<String, Collection<String>>> promoterMap = ioPromoters.readFile();
		InFlatFile ioGenes = new InFlatFile(fileGenes);
		Map<String,Map<String, Collection<String>>> geneMap = ioGenes.readFile();

		Map<String, Collection<String>> regulationGenes = new TreeMap<String, Collection<String>>();
		Map<String, Collection<String>> regulationTUs = new TreeMap<String, Collection<String>>();
		Map<String, String> regulationMode = new TreeMap<String, String>();
		for (Entry<String, Map<String, Collection<String>>> entry : regulationMap.entrySet())
		{
			String mode = null;
			if (entry.getValue().containsKey(REGULATOR_MODE))
			{
				mode = entry.getValue().get(REGULATOR_MODE).iterator().next();
				if (entry.getValue().get(REGULATOR_MODE).size()>1)
				{
					System.err.println("Warning: regulation mode information not as supposed");
				}
			}
			Collection<String> regulatedGenes = new TreeSet<String>();
			Collection<String> regulatedTUs = new TreeSet<String>();
			//get the regulated entities
			if (entry.getValue().containsKey(REGULATED_ENTITY))
			{
				for (String regulated: entry.getValue().get(REGULATED_ENTITY))
				{
					// get the promoters of regulated by the regulation entity
					if(promoterMap.containsKey(regulated))
					{
						Map<String, Collection<String>> pro = promoterMap.get(regulated);
						//get TU in which the promoter is used
						if (pro.containsKey(COMPONENT_OF))
						{
							Collection<String> componentsTU = pro.get(COMPONENT_OF);
							regulatedTUs.addAll(componentsTU); //potential TUs
							for(String component : componentsTU)
							{						
								//get TUs
								if (tuMap.containsKey(component))
								{
									Map<String, Collection<String>> tu = tuMap.get(component);
									// get components of the TUs including genes
									if (tu.containsKey(COMPONENTS))
									{
										regulatedGenes.addAll(tu.get(COMPONENTS)); //potential genes, but not only genes
									}
								}	
							}
						}
					}
					if (tuMap.containsKey(regulated))
					{
						Map<String, Collection<String>> tu = tuMap.get(regulated);
						regulatedTUs.add(regulated); //potential TUs
						// get components of the TUs including genes
						if (tu.containsKey(COMPONENTS))
						{
							regulatedGenes.addAll(tu.get(COMPONENTS)); //potential genes, but not only genes
						}
					}
				}
			}
			Set<String> regulators = new HashSet<String>();
			if (entry.getValue().containsKey(REGULATOR))
			{
				regulators.addAll(entry.getValue().get(REGULATOR));
			}
			else
			{
				regulators.add(entry.getKey());
			}
			regulatedGenes.retainAll(geneMap.keySet());
			regulatedTUs.retainAll(tuMap.keySet());
			for (String key : regulators)
			{
				Collection<String> genesSet = regulationGenes.get(key);
				if (genesSet == null)
				{
					//System.err.println("Error: Key "+ key + " already exists:\n" +
					//		"values in map: " + regulationGenes.get(key) +
					//		"\nnew values:    " + regulatedGenes);
					//System.exit(-1);
					genesSet = new TreeSet<String>();
					regulationGenes.put(key, genesSet);
				}
				genesSet.addAll(regulatedGenes);

				Collection<String> tuSet = regulationTUs.get(key);
				if (tuSet == null)
				{
					//System.err.println("Error: Key "+ key + " already exists:\n" +
					//		"values in map: " + regulationGenes.get(key) +
					//		"\nnew values:    " + regulatedGenes);
					//System.exit(-1);
					tuSet = new TreeSet<String>();
					regulationTUs.put(key, tuSet);
				}
				tuSet.addAll(regulatedTUs);
			}
			regulationMode.put(entry.getKey(), mode);

		}

		Map<String, Collection<String>> output = null;
		if(directRegulation.equals("d"))
		{
			output = regulationGenes;
		}
		if (directRegulation.equals("i"))
		{
			System.err.println("Not implemented");
		}

		BufferedWriter out = new BufferedWriter(new FileWriter(fileOut));
		for (Entry<String, Collection<String>> entry : output.entrySet())
		{
			if (! entry.getValue().isEmpty())
			{
				out.write(entry.getKey() + "\t" + entry.getValue().toString().replaceAll("[\\[\\],]", "")+"\n");
			}
		}
		out.close();
	}

}
